/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * My Version Class
 *      Provides class for extracting A.I. assembly version information.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.Threading;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Reflection.Emit;

namespace Adaptive.Foundation
{
    /// <summary>
    /// Provides class for extracting A.I. assembly version information.
    /// </summary>
    public sealed class MyVersion : DisposableObjectBase 
    {
        /*--------------------------------------------------------------------------------
         * Private Member Declarations
         *------------------------------------------------------------------------------*/
        #region Private Member Declarations

        private MyVersionSources _source = MyVersionSources.CurrentClassLibrary;

        private string _fullName = string.Empty;
        private string _imageRuntimeVersion = string.Empty;
        private string _location = string.Empty;

        private bool _comVisible;
        private bool _wrapNonExceptions;
        private bool _optimizerDisabled;
        private bool _jitTracking;

        private string _product = string.Empty;
        private string _company = string.Empty;
        private string _tradeMark = string.Empty;
        private string _copyRight = string.Empty;
        private string _configuration = string.Empty;
        private string _fileVersion = string.Empty;
        private string _infoVersion = string.Empty;
        private string _description = string.Empty;
        private string _culture = string.Empty;
        private string _defaultAlias = string.Empty;
        private string _title = string.Empty;

        private int _relaxations;
        private uint _algorithmId;
        private System.Diagnostics.DebuggableAttribute.DebuggingModes _debugFlags = System.Diagnostics.DebuggableAttribute.DebuggingModes.Default;

        private Guid _guid = Guid.Empty;

        #endregion

        /*--------------------------------------------------------------------------------
         * Constructor / Dispose / Destructor Methods
         *------------------------------------------------------------------------------*/
        #region Constructor / Dispose / Destructor Methods
        /// <summary>
        /// Initializes a new instance of the class.
        /// </summary>
        /// <remarks>
        /// This is the default constructor.
        /// 
        /// This will default to reading the current class library's version
        /// information.
        /// </remarks>
        public MyVersion()
            : base()
        {
            ExtractVersionData();
        }
        /// <summary>
        /// Initializes a new instance of the class to read the version information
        /// from the specified source.
        /// </summary>
        /// <param name="source">
        /// A <see cref="MyVersionSources"/> enumerated value indicating from where to 
        /// read the versioning data.
        /// </param>
        public MyVersion(MyVersionSources source)
        {
            _source = source;
            ExtractVersionData();
        }
        /// <summary>
        /// Deallocates internally allocated objects.
        /// </summary>
        /// <param name="disposing">
        /// A value indicating whether the object is being disposed.
        /// </param>
        protected override void Dispose(bool disposing)
        {
            _fullName = null;
            _imageRuntimeVersion = null;
            _location = null;
            _product = null;
            _company = null;
            _tradeMark = null;
            _copyRight = null;
            _configuration = null;
            _fileVersion = null;
            _infoVersion = null;
            _description = null;
            _culture = null;
            _defaultAlias = null;
            _title = null;
            _guid = Guid.Empty;
            base.Dispose(disposing);
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Properties
         *------------------------------------------------------------------------------*/
        #region Public Properties
        /// <summary>
        /// Gets the hash algorithm of an assembly manifest's contents.
        /// </summary>
        /// <value>
        /// An unsigned integer representing the assembly hash algorithm.
        /// </value>
        public uint AlgorithmId
        {
            get { return _algorithmId; }
        }
        /// <summary>
        /// Gets the name of the company which manufactured the product.
        /// </summary>
        /// <value>
        /// The manufacturing or registered company name.
        /// </value>
        public string Company
        {
            get { return _company; }
        }
        /// <summary>
        /// Gets a value indicating wheter the assembly is visible to COM.
        /// </summary>
        /// <value>
        /// <b>true</b> if the <b>ComVisible</b> attribute is <b>true</b>; otherwise, <b>false</b>.
        /// </value>
        public bool ComVisible
        {
            get { return _comVisible; }
        }
        /// <summary>
        /// Gets the copyright text associated with the product.
        /// </summary>
        /// <value>
        /// The text describing the product copyright information.
        /// </value>
        public string Copyright
        {
            get { return _copyRight; }
        }
        /// <summary>
        /// Gets the configuration description for the loaded assembly.
        /// </summary>
        /// <value>
        /// A product or assembly configuration description.
        /// </value>
        public string Configuration
        {
            get { return _configuration; }
        }
        /// <summary>
        /// Gets the name of the culture for which the assembly was designed.
        /// </summary>
        /// <value>
        /// A standard language/culture identifier or name.
        /// </value>
        public string Culture
        {
            get { return _culture; }
        }
        /// <summary>
        /// Gets the debugging modes for the attribute.
        /// </summary>
        /// <value>
        ///  bitwise combination of the <see cref="System.Diagnostics.DebuggableAttribute.DebuggingModes"/> values 
        /// describing the debugging mode for the just-in-time (JIT) compiler.
        /// </value>
        public System.Diagnostics.DebuggableAttribute.DebuggingModes DebugFlags
        {
            get { return _debugFlags; }
        }
        /// <summary>
        /// Gets default alias information.
        /// </summary>
        /// <value>
        /// A string containing the default alias information.
        /// </value>
        public string DefaultAlias
        {
            get { return _defaultAlias; }
        }
        /// <summary>
        /// Gets the description of the assembly.
        /// </summary>
        /// <value>
        /// A text description value.
        /// </value>
        public string Description
        {
            get { return _description; }
        }
        /// <summary>
        /// Gets the file version for the assembly.
        /// </summary>
        /// <value>
        /// The version of the assembly file.
        /// </value>
        public string FileVersion
        {
            get { return _fileVersion; }
        }
        /// <summary>
        /// Gets the display name of the assembly.
        /// </summary>
        /// <value>
        /// The display name of the assembly.
        /// </value>
        public string FullName
        {
            get{return _fullName;}
        }
        /// <summary>
        /// Gets the GUID assigned to the assembly.
        /// </summary>
        /// <value>
        /// The <see cref="Guid"/> assigned to the assembly.
        /// </value>
        public Guid Guid
        {
            get { return _guid; }
        }
        /// <summary>
        /// Gets a string representing the version of the common language runtime (CLR) saved 
        /// in the file containing the manifest.
        /// </summary>
        /// <value>
        /// A string representing the CLR version folder name. This is not a full path.
        /// </value>
        public string ImageRuntimeVersion
        {
            get { return _imageRuntimeVersion; }
        }
        /// <summary>
        /// Gets the information version string for the assembly and/or product.
        /// </summary>
        /// <value>
        /// The product or assembly information version information.
        /// </value>
        public string InfoVersion
        {
            get { return _infoVersion; }
        }
        /// <summary>
        /// Gets a value indicating whether the JIT optimizer is disabled for this assembly.
        /// </summary>
        /// <value>
        /// <b>true</b> if the JIT optimizer is disabled for this assembly, otherwise, <b>false</b>.
        /// </value>
        public bool JitOptimizerDisabled
        {
            get { return _optimizerDisabled; }
        }
        /// <summary>
        /// Gets a value that indicates whether the runtime will track information during code generation for the debugger.
        /// </summary>
        /// <value>
        /// <b>true</b> if the runtime will track information during code generation for the debugger; otherwise, <b>false</b>.
        /// </value>
        public bool JitTrackingEnabled
        {
            get { return _jitTracking; }
        }
        /// <summary>
        /// Gets the path or UNC location of the loaded file that contains the manifest.
        /// </summary>
        /// <value>
        /// The location of the loaded file that contains the manifest. If the loaded file was shadow-copied, 
        /// the location is that of the file after being shadow-copied. 
        /// </value>
        public string Location
        {
            get { return _location; }
        }
        /// <summary>
        /// Gets the name of the product to which the assembly belongs.
        /// </summary>
        /// <value>
        /// The product name.
        /// </value>
        public string Product
        {
            get { return _product; }
        }
        /// <summary>
        /// Gets the compilation relaxations specified when the current object was constructed.
        /// </summary>
        /// <value>
        /// A <see cref="CompilationRelaxations"/> enumerated value indicating the compilation 
        /// relaxations specified when the current object was constructed.
        /// </value>
        public CompilationRelaxations Relaxations
        {
            get { return (CompilationRelaxations)_relaxations; }
        }
        /// <summary>
        /// Gets the trademark text associated with the product.
        /// </summary>
        /// <value>
        /// The text describing the product trademark information.
        /// </value>
        public string TradeMark
        {
            get { return _tradeMark; }
        }
        /// <summary>
        /// Gets assembly title information.
        /// </summary>
        /// <value>
        /// A string containing the assembly title.
        /// </value>
        public string Title
        {
            get { return _title; }
        }
        /// <summary>
        /// Gets a value that indicates whether to wrap exceptions that do not derive from the 
        /// <b>Exception</b> class with a <see cref="RuntimeWrappedException"/> object.
        /// </summary>
        /// <value>
        /// <b>true</b> if exceptions that do not derive from the <see cref="Exception"/> class should appear wrapped with 
        /// a <see cref="RuntimeWrappedException"/> object; otherwise, <b>false</b>. 
        /// </value>
        public bool WrapNonExceptions
        {
            get { return _wrapNonExceptions; }
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Methods / Functions
        /// <summary>
        /// Clears the values of the property contents.
        /// </summary>
        public void Clear()
        {
            _fullName = string.Empty;
            _imageRuntimeVersion = string.Empty;
            _location = string.Empty;
            _product = string.Empty;
            _company = string.Empty;
            _tradeMark = string.Empty;
            _copyRight = string.Empty;
            _configuration = string.Empty;
            _fileVersion = string.Empty;
            _infoVersion = string.Empty;
            _description = string.Empty;
            _culture = string.Empty;
            _defaultAlias = string.Empty;
            _title = string.Empty;
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Private Methods / Functions
        /// <summary>
        /// Execcutes the extraction process in a seperate thread so the assembly reference
        /// can be unloaded.
        /// </summary>
        private void ExtractVersionData()
        {
            Thread itemToExecute = null;

            itemToExecute = new Thread(new ThreadStart(VersionExtractionThread));
            itemToExecute.Priority = ThreadPriority.Highest;
            itemToExecute.IsBackground = true;
            itemToExecute.Start();
            itemToExecute.Join();
            itemToExecute = null;
        }
        /// <summary>
        /// Extracts the version information from the current assembly.
        /// </summary>
        private void VersionExtractionThread()
        {
            Assembly current = null;                    //Current assembly pointer.
            object[] content = null;                    //Custom attributes.

            //Get the current assembly reference and basic data.
            try
            {
                switch (_source)
                {
                    case MyVersionSources.CurrentClassLibrary:
                        current = Assembly.GetExecutingAssembly();
                        break;

                    case MyVersionSources.CallingAssembly:
                        current = Assembly.GetCallingAssembly();
                        break;

                    case MyVersionSources.CurrentExecutable:
                        current = Assembly.GetEntryAssembly();
                        break;
                }

                _fullName = current.FullName;
                _imageRuntimeVersion = current.ImageRuntimeVersion;
                _location = current.Location;
            }
            catch
            {
                current = null;
            }

            //Read the custom attributes.
            if (current != null)
            {
                try
                {
                    content = current.GetCustomAttributes(false);
                }
                catch
                {
                    content = null;
                }

                if (content != null)
                {
                    foreach (object item in content)
                    {
                        try
                        {
                            ProcessItem(item);
                        }
                        catch
                        {
                        }
                    }
                    Array.Clear(content, 0, content.Length);
                }
            }
            content = null;
            current = null;
        }
        /// <summary>
        /// Processes the information stored in the object based on its type.
        /// </summary>
        /// <param name="item">
        /// A custom attribute instance containing the version data.
        /// </param>
        private void ProcessItem(object item)
        {
            if (item != null)
            {
            if (item is ComVisibleAttribute)
            {
                _comVisible = ((ComVisibleAttribute)item).Value;
            }
            else if (item is AssemblyTrademarkAttribute)
            {
                _tradeMark = ((AssemblyTrademarkAttribute)item).Trademark;
            }
            else if (item is RuntimeCompatibilityAttribute)
            {
                _wrapNonExceptions = ((RuntimeCompatibilityAttribute)item).WrapNonExceptionThrows;
            }
            else if (item is System.Reflection.AssemblyProductAttribute)
            {
                _product = ((AssemblyProductAttribute)item).Product;
            }
            else if (item is System.Reflection.AssemblyCompanyAttribute)
            {
                _company = ((AssemblyCompanyAttribute)item).Company;
            }
            else if (item is CompilationRelaxationsAttribute)
            {
                _relaxations = ((CompilationRelaxationsAttribute)item).CompilationRelaxations;
            }
            else if (item is GuidAttribute)
            {
                _guid = new Guid(((GuidAttribute)item).Value);
            }
            else if (item is AssemblyCopyrightAttribute)
            {
                _copyRight = ((AssemblyCopyrightAttribute)item).Copyright;
            }
            else if (item is AssemblyConfigurationAttribute)
            {
                _configuration = ((AssemblyConfigurationAttribute)item).Configuration;
            }
            else if (item is AssemblyFileVersionAttribute)
            {
                _fileVersion = ((AssemblyFileVersionAttribute)item).Version;
            }
            else if (item is AssemblyDescriptionAttribute)
            {
                _description = ((AssemblyDescriptionAttribute)item).Description;
            }
            else if (item is AssemblyTitleAttribute)
            {
               _title =  ((AssemblyTitleAttribute)item).Title;
            }
            else if (item is AssemblyAlgorithmIdAttribute)
            {
                _algorithmId = ((AssemblyAlgorithmIdAttribute)item).AlgorithmId;
            }
            else if (item is AssemblyCultureAttribute)
            {
                _culture = ((AssemblyCultureAttribute)item).Culture;
            }
            else if (item is AssemblyDefaultAliasAttribute)
            {
                _defaultAlias = ((AssemblyDefaultAliasAttribute)item).DefaultAlias;
            }
            else if (item is AssemblyInformationalVersionAttribute)
            {
                _infoVersion = ((AssemblyInformationalVersionAttribute)item).InformationalVersion;
            }
            else if (item is System.Diagnostics.DebuggableAttribute)
            {
                System.Diagnostics.DebuggableAttribute attrib = ((System.Diagnostics.DebuggableAttribute)item);

                _debugFlags = attrib.DebuggingFlags;
                _optimizerDisabled = attrib.IsJITOptimizerDisabled;
                _jitTracking = attrib.IsJITTrackingEnabled;

            }
            }
        }
        #endregion
    }
}
